/*
 * Copyright (c)  2018, XiQiao
 * All rights reserved. 
 *
 * Id:ExcelMappingFactory.java   2018-07-26 22:21 wanglijun
 */
package io.marmot.poi.factory;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Lists;
import io.marmot.poi.annotation.Excel;
import io.marmot.poi.annotation.ExcelField;
import io.marmot.poi.config.Options;
import io.marmot.poi.converter.ReadConverter;
import io.marmot.poi.converter.WriteConverter;
import io.marmot.poi.domain.ExcelMapping;
import io.marmot.poi.domain.ExcelProperty;
import io.marmot.poi.domain.ExcelPropertyComparator;
import io.marmot.poi.exception.ExcelAnnotationAnalyzeException;
import io.marmot.poi.exception.ExcelConfigAnalyzeFailedException;
import io.marmot.poi.util.ValidatorUtil;
import io.marmot.poi.validator.Validator;

import java.lang.reflect.Field;
import java.util.Collections;
import java.util.List;

/**
 * <p>
 * Title:
 * </p>
 * <p>
 * Description:
 * </p>
 * <p>
 * Copyright: Copyright (c) 2018
 * </p>
 * <p>
 * Company: XiQiao
 * </p>
 *
 * @author: wanglijun
 * @create: 2018-07-26 22:21
 * @version：1.0
 */
public class ExcelMappingFactory {


    private final static LoadingCache<Class<?>, ExcelMapping> excelMappingLoadingCache =
            CacheBuilder.newBuilder()
                    .maximumSize(100)
                    .build(new CacheLoader<Class<?>, ExcelMapping>() {
                        @Override
                        public ExcelMapping load(Class<?> key) {
                            return loadExcelMappingByClass(key);
                        }
                    });


    /**
     * 获取指定实体的Excel映射信息
     *
     * @return ExcelMapping
     */
    public static ExcelMapping get(Class<?> clazz) {
        try {
            return excelMappingLoadingCache.get(clazz);
        } catch (Exception e) {
            throw new ExcelConfigAnalyzeFailedException (e);
        }
    }

    private static ExcelMapping loadExcelMappingByClass(Class<?> clazz){
        ExcelMapping excelMapping = null;
        try {
            excelMapping = loadExcelMappingByAnnotation(clazz);
        } catch (Exception e) {
            throw new ExcelConfigAnalyzeFailedException(e);
        }
        return excelMapping;
    }

    private static ExcelMapping loadExcelMappingByAnnotation(Class<?> clazz)
            throws IllegalAccessException, InstantiationException {
        ExcelMapping excelMapping = new ExcelMapping();
        Excel excel = clazz.getAnnotation(Excel.class);
        if (null == excel) {
            throw new ExcelAnnotationAnalyzeException(
                    "[" + clazz.getName() + "] @Excel annotations not found.");
        }
        excelMapping.setName(excel.value());
        excelMapping.setTitle (excel.title ());
        ExcelProperty excelMappingProperty;
        Field[] fields = clazz.getDeclaredFields();
        List<ExcelProperty> propertyList = Lists.newArrayList();
        for (Field field : fields) {
            ExcelField excelField = field.getAnnotation(ExcelField.class);
            if (null != excelField) {
                Options options = excelField.options().equals(ExcelField.DefaultAnnotation.class) ? null
                        : excelField.options().newInstance();
                WriteConverter writeConverter =
                        excelField.writeConverter().equals(ExcelField.DefaultAnnotation.class) ? null
                                : excelField.writeConverter().newInstance();
                ReadConverter readConverter =
                        excelField.readConverter().equals(ExcelField.DefaultAnnotation.class) ? null
                                : excelField.readConverter().newInstance();
                Validator validator =
                        excelField.validator().equals(ExcelField.DefaultAnnotation.class) ? null
                                : excelField.validator().newInstance();


                excelMappingProperty = ExcelProperty.builder()
                        .name(ValidatorUtil.isEmpty(excelField.name()) ? field.getName() : excelField.name())
                        .required(excelField.required())
                        .column(ValidatorUtil.isEmail(excelField.value()) ? field.getName() : excelField.value())
                        .comment(excelField.comment())
                        .maxLength(excelField.maxLength())
                        .width(excelField.width())
                        .dateFormat(excelField.dateFormat())
                        .options(options)
                        .writeConverterExp(excelField.writeConverterExp())
                        .writeConverter(writeConverter)
                        .readConverterExp(excelField.readConverterExp())
                        .readConverter(readConverter)
                        .regularExp(excelField.regularExp())
                        .regularExpMessage(excelField.regularExpMessage())
                        .validator(validator)
                        .order (excelField.order ())
                        .build();
                propertyList.add(excelMappingProperty);
            }
        }
        if (propertyList.isEmpty()) {
            throw new ExcelAnnotationAnalyzeException (
                    "[" + clazz.getName() + "] @ExcelField annotations not found.");
        }
        Collections.sort(propertyList,new ExcelPropertyComparator ());
        excelMapping.setPropertyList(propertyList);
        return excelMapping;
    }
}
